﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using DomainDriver.DomainModeling.DomainObjects;

namespace DomainDriver.DomainModeling.StorageManagers
{
    public enum EntityKeyMatcherType
    {
        Func,
        Expression,
        SqlQuery
    }

    public class EntityKeyMatcher<KEY, KEYED_DOMAIN_OBJECT>
        where KEYED_DOMAIN_OBJECT : class, IKeyedDomainObject<KEY, KEYED_DOMAIN_OBJECT>
    {
        public EntityKeyMatcher(Func<KEYED_DOMAIN_OBJECT, bool> funcValue)
        {
            KeyMatcherType = EntityKeyMatcherType.Func;
            FuncValue = funcValue;
        }

        public EntityKeyMatcher(Expression<Func<KEYED_DOMAIN_OBJECT, bool>> expressionValue)
        {
            KeyMatcherType = EntityKeyMatcherType.Expression;
            ExpressionValue = expressionValue;
        }

        public EntityKeyMatcher(DbSqlQuery<KEYED_DOMAIN_OBJECT> sqlQueryValue)
        {
            KeyMatcherType = EntityKeyMatcherType.SqlQuery;
            SqlQueryValue = sqlQueryValue;
        }

        public EntityKeyMatcherType KeyMatcherType { get; protected set; }
        public Func<KEYED_DOMAIN_OBJECT, bool> FuncValue { get; protected set; }
        public Expression<Func<KEYED_DOMAIN_OBJECT, bool>> ExpressionValue { get; protected set; }
        public DbSqlQuery<KEYED_DOMAIN_OBJECT> SqlQueryValue { get; protected set; }

        public IEnumerable<KEYED_DOMAIN_OBJECT> DoWhere(IQueryable<KEYED_DOMAIN_OBJECT> dataStore)
        {
            if (KeyMatcherType == EntityKeyMatcherType.Func)
            { return dataStore.Where(FuncValue); }
            else if (KeyMatcherType == EntityKeyMatcherType.Expression)
            { return dataStore.Where(ExpressionValue); }
            else if (KeyMatcherType == EntityKeyMatcherType.SqlQuery)
            { return SqlQueryValue; }
            else
            { throw new InvalidOperationException("DoWhere is not implemented for the specified type."); }
        }
    }
}